home *** CD-ROM | disk | FTP | other *** search
/ Aminet 23 / Aminet 23 (1998)(GTI - Schatztruhe)[!][Feb 1998].iso / Aminet / dev / e / ebuild.lha / build / Build.e < prev    next >
Text File  |  1997-12-14  |  16KB  |  549 lines

  1. /* build in E.
  2.  
  3. TODO:    - cyclic structure check (part)
  4.     - (amigados?) constants (part)
  5.  
  6. */
  7.  
  8. OPT OSVERSION=37
  9.  
  10. MODULE 'tools/file', 'dos/dosextens', 'dos/dos','dos/dostags'
  11.  
  12. /*
  13.   symbol=object
  14.   object: dep1 dep2 ....
  15.      act1
  16.      act2
  17.  
  18.   $(symbol): $(symbol)bla ....
  19.      act1
  20.      ...
  21. */
  22.  
  23. /*
  24. history:
  25.  
  26. (Version 0.8 by Rob and Wouter, lost modifications for 3.2 by Jason)
  27.  
  28. When        Who        What
  29. 23.07.97    Glauschwuffel    - Added symbolic constants. Constants are allowed everywhere
  30. 26.07.97    Glauschwuffel    - Removed bug in constants: The part after the last constant
  31.                   wouldn't be copied. $(test): $(test).e crashed in cyclic
  32.                   dependancy. :(
  33.                 - Used source that Jason mailed me to get right order of actions.
  34.                 - Minor modification in traverse(): "circ" is raised when object
  35.                   and a dependancy have the same name. 
  36.                 - Added version facility :)
  37.                 - local constant $(target) is now available in actions
  38.                 - Added QUIET arg
  39. 27.07.97    Glauschwuffel    - Changed QUIET to VERBOSE since quiet was default for v3.1
  40. (between        Glauschwuffel   - Used EBuild with new oomodules/ objects. *Very* stable, no errrors
  41.                                           at all. I tend to say it's error-free <g>)
  42. 09.08.97    Glauschwuffel    - Actions of a target are now collected in a script again.
  43.                                           EBuild now acts as described in the Ev3.2 doc (except of the
  44.                                           modified $target). Bumped version to 0.9.
  45. 10.08.97    Glauschwuffel    - Added script variable $target for reasons of consistency. Now
  46.                                           $(target) and $target are possible.
  47.                                           Discovered a potential bug: if build is called without a target and
  48.                                           the first target in the buildfile is not a filename (e.g. a symbolic
  49.                                   target like `all' or `clean') the actions for this target are
  50.                                   executed anyway (0.8 does this, too).
  51. 05.09.97    Glauschwuffel    - BUG: the temporary script in T: won't be closed on exceptions
  52.                   Fixed.
  53. 13.09.97    Glauschwuffel    - ADD: commandline option CONSTANTS. Lists the constants before executing
  54.                   anything. Modified `dumpC()' for this.
  55. 12.10.97    Glauschwuffel    - BUG: EBuild would cause an enforcer hit when no dependent objects are
  56.                   specified (as with symbolic targets like 'clean'). target was only set
  57.                   when there were dependencies, moved the statement two lines higher.
  58.                   Fixed. Bumped version. Thanks to Nuno for the report.
  59. 16.11.97    Glauschwuffel    - ADD: script variable DEP holds the name of
  60.                   the first dependancy. (used to avoid conflicts with <.)
  61.                   Expanded 'depedancy' object with 'lastdep'.
  62.                   BUG: dependancies were in wrong order as with the actions.
  63. 22.11.97    Glauschwuffel    - ADD: include directive. This one's pretty recursive.
  64. 23.11.97    Glauschwuffel    - BUG: Using the FROM argument took the name but added a '.build'.
  65.                   ADD: constants in constants. Argument MESS (don't delete script).
  66.                   BUG: Jason wasn't in the copyright line :)
  67.                   CHG: script name is target dependent so MESS is useful.
  68.                   BUG: $(dep) was set even if there was no dependancy.
  69.                   CHG: Bumped version to 0.97
  70. */
  71.  
  72. OBJECT object
  73.   next:PTR TO object
  74.   name:PTR TO CHAR
  75.   firstdep:PTR TO dependancy
  76.   firstaction:PTR TO action
  77.   child
  78.   lastaction:PTR TO action
  79.   lastdep:PTR TO dependancy
  80. ENDOBJECT
  81.  
  82. OBJECT dependancy
  83.   next:PTR TO dependancy
  84.   object:PTR TO object
  85. ENDOBJECT
  86.  
  87. OBJECT action
  88.   next:PTR TO action
  89.   comstring:PTR TO CHAR
  90. ENDOBJECT
  91.  
  92. OBJECT arg
  93.   target,buildfile,force,verbose,nohead,constants,mess
  94. ENDOBJECT
  95.  
  96. OBJECT constant
  97.   next:PTR TO constant
  98.   name:PTR TO CHAR
  99.   subst:PTR TO CHAR
  100. ENDOBJECT
  101.  
  102. DEF curline=0, curstring, uptodate=TRUE, args:PTR TO arg,
  103.     constants:PTR TO constant, -> global list of constants in reverse order
  104.     target:PTR TO CHAR, -> holds name of current target
  105.     depName:PTR TO CHAR -> holds current first dependancy
  106.  
  107. PROC main() HANDLE
  108.   DEF m,l,buildfile[200]:STRING,rdargs=NIL,list,nulist
  109.  
  110.   NEW args
  111.   IF (rdargs:=ReadArgs('TARGET,FROM/K,FORCE/S,VERBOSE/S,NOHEAD/S,CONSTANTS/S,MESS/S',args,NIL))=NIL THEN Raise("barg")
  112.   IF args.buildfile
  113.     StrCopy(buildfile,args.buildfile)
  114.   ELSE
  115.     StrAdd(buildfile,'.build')
  116.   ENDIF
  117.  
  118.   IF (args.nohead = 0) -> be VERY quiet
  119.     PrintF({versionString})
  120.     PrintF(' (processing "\s")\n', buildfile)
  121.   ENDIF
  122.   m,l:=readfile(buildfile)
  123.   list:=stringsinfile(m,l,countstrings(m,l))
  124.   WHILE (nulist:=lookForDirectives(list)) <> list DO list:=nulist
  125.   list:=nulist
  126.   buildtree(parse(list))
  127.   IF uptodate THEN PrintF('All files are up to date.\n')
  128.   Raise()
  129. EXCEPT
  130.   IF rdargs THEN FreeArgs(rdargs)
  131.   IF exception=0 THEN RETURN
  132.   PrintF('Error: ')
  133.   SELECT exception
  134.     CASE "OPEN"
  135.       PrintF('Couldn''t open "\s".\n',exceptioninfo)
  136.     CASE "MEM"
  137.       PrintF('Not enough memory.\n')
  138.     CASE "IN"
  139.       PrintF('Couldn''t read file.\n')
  140.     CASE "nobj"
  141.       PrintF('Action without object.\n')
  142.     CASE "fexp"
  143.       PrintF('Filename expected.\n')
  144.     CASE "dexp"
  145.       PrintF('":" or "=" expected.\n')
  146.     CASE "empt"
  147.       PrintF('Nothing to build.\n')
  148.     CASE "circ"
  149.       PrintF('Circular dependancies at file "\s".\n', exceptioninfo)
  150.     CASE "bada"
  151.       PrintF('Action failed to build "\s".\n',exceptioninfo)
  152.     CASE "badd"
  153.       PrintF('Dependancy "\s" not available.\n',exceptioninfo)
  154.     CASE "derr"
  155.       PrintF('Child process failed (actions script failed).\n')
  156.     CASE "ntar"
  157.       PrintF('No such target: "\s".\n',args.target)
  158.     CASE "ndep"
  159.       PrintF('No dependancies for object "\s".\n',exceptioninfo)
  160.     CASE "clos"
  161.       PrintF('Missing closing brace: "\s".\n',exceptioninfo)
  162.     CASE "cons"
  163.       PrintF('Unknown constant: "\s".\n',exceptioninfo)
  164.       dumpC()
  165.     CASE "barg"
  166.       PrintFault(IoErr(),NIL)
  167.     CASE "scrp"
  168.       PrintF ('Unable to create temporary script.\n')
  169.     CASE "inc"
  170.       WriteF ('Unable to open include file \a\s\a.\n',exceptioninfo)
  171.     DEFAULT
  172.       PrintF('burp.\n')
  173.   ENDSELECT
  174.   IF curline THEN PrintF('at line: (\d) "\s"\n',curline,curstring)
  175.   IF exception THEN PrintF('Build terminated\n')
  176.   RETURN 10
  177. ENDPROC
  178.  
  179. PROC parse(list:PTR TO LONG)
  180. -> i holds the name of the constant/action
  181. -> t points to i's tail
  182.  
  183.   DEF l=NIL:PTR TO object, s, c, i, t, const=NIL:PTR TO constant,str:PTR TO CHAR
  184.   FOR curline:=0 TO ListLen(list)-1
  185.     s:=list[curline]
  186.     curstring:=s
  187.     c:=s[]
  188.     IF (c<>"#") AND (c<>"\0")            -> ignore?
  189.       IF (c=" ") OR (c="\t")            -> action
  190.         s:=eatwhite(s)
  191.         IF s[]
  192.           IF l=NIL THEN Raise("nobj")
  193.           -> was: l.firstaction:=NEW [l.firstaction,s]:action
  194.             -> replaced by the following IF (Rob through Glauschwuffel)
  195.             IF l.lastaction
  196.               l.lastaction.next:=NEW [NIL,s]:action
  197.               l.lastaction:=l.lastaction.next
  198.             ELSE
  199.               l.firstaction:=NEW [NIL,s]:action
  200.               l.lastaction:=l.firstaction
  201.             ENDIF
  202.         ENDIF
  203.       ELSE                    -> object rule or constant
  204.         i:=s -> i holds the name
  205.         s:=eatname(s)
  206.         IF s=i THEN Raise("fexp")
  207.         t:=s
  208.  
  209.     IF (s[]<>":") AND (s[]<>"=") THEN Raise("dexp")
  210.         IF s[]=":"
  211.  
  212.       -> check object rule for use of constants
  213.       str:=String(1024) -> dyn. alloc., free if no constants 
  214.       IF str=NIL THEN Raise("MEM")
  215.  
  216.       substituteConstants (i, str)
  217.       i := str; s:=eatname(str) 
  218.           IF s=i THEN Raise("fexp")
  219.           t:=s
  220.           t[]:="\0"
  221.             s++
  222.           s:=eatwhite(s)
  223.           l:=NEW [l,i,NIL,NIL,0]:object
  224.           s:=eatwhite(s)
  225.           IF s[]<>"\0"
  226.             REPEAT
  227.               i:=s
  228.               s:=eatname(s)
  229.               t:=s
  230.               IF t=i THEN Raise("fexp")
  231.               s:=eatwhite(s)
  232.               t[]:="\0"
  233.               -> 16.11.97 was: l.firstdep:=NEW [l.firstdep,i]:dependancy
  234.                 IF l.lastdep
  235.                   l.lastdep.next:=NEW [NIL,i]:dependancy
  236.                   l.lastdep:=l.lastdep.next
  237.                 ELSE
  238.                   l.firstdep:=NEW [NIL,i]:dependancy
  239.                   l.lastdep:=l.firstdep
  240.                 ENDIF
  241.  
  242.             UNTIL s[]="\0"
  243.           ENDIF
  244.           ELSE -> we have a constant
  245.  
  246.       -> check rule for use of constants
  247.       str:=String(1024) -> dyn. alloc., free if no constants 
  248.       IF str=NIL THEN Raise("MEM")
  249.  
  250.       substituteConstants (i, str)
  251.           i := str; s:=eatname(str) 
  252.           IF s=i THEN Raise("fexp")
  253.           t:=s
  254.  
  255.           t[]:="\0" -> terminate name
  256.            s++
  257.            s:=eatwhite(s)
  258.       const:=NEW[const,i,s]:constant
  259.       constants:=const -> have to do it here so consts in rules are recognized
  260.           ENDIF
  261.       ENDIF
  262.     ENDIF
  263.   ENDFOR
  264.   curline:=0
  265.   IF args.constants THEN dumpC()
  266.   IF l=NIL THEN Raise("empt")
  267. ENDPROC l
  268.  
  269.  
  270. PROC eatwhite(s)
  271.   WHILE (s[]=" ") OR (s[]="\t") DO s++
  272. ENDPROC s
  273.  
  274. PROC eatname(s)
  275.   WHILE (s[]<>" ") AND (s[]<>"\t") AND (s[]<>"\0") AND (s[]<>":") AND (s[]<>"=") DO s++
  276. ENDPROC s
  277.  
  278. /* obsolete
  279. PROC execute(c)
  280. DEF s[1024]:STRING
  281.   uptodate:=FALSE
  282.   substituteConstants (c, s)
  283.   IF args.verbose THEN PrintF('\s\n', s)
  284.   IF Execute(s,NIL,stdout)=NIL THEN Raise("derr")
  285. ENDPROC */
  286.  
  287. PROC filetime(name:PTR TO CHAR)
  288.   DEF l:PTR TO filelock, fib:fileinfoblock, date:PTR TO datestamp
  289.   IF l:=Lock(name,ACTION_READ)
  290.     IF Examine(l,fib)
  291.       date:=fib.datestamp
  292.       IF fib.direntrytype<0
  293.         UnLock(l)
  294.         RETURN date.days, Shl(date.minute,12)+date.tick
  295.       ENDIF
  296.     ENDIF
  297.     UnLock(l)
  298.   ENDIF
  299. ENDPROC -1
  300.  
  301. PROC timelater(day1,tick1,day2,tick2)
  302.   IF day1>day2
  303.     RETURN TRUE
  304.   ELSEIF day1=day2
  305.     RETURN tick1>tick2
  306.   ENDIF
  307. ENDPROC FALSE
  308.  
  309. /*----------------rob's-stuff-------------------*/
  310.  
  311. PROC buildtree(list:PTR TO object) -> returns root of tree
  312.   DEF dep:PTR TO dependancy,
  313.       obj:PTR TO object
  314.  
  315.   obj:=list
  316.   WHILE obj         -> traverse objects
  317.     dep:=obj.firstdep
  318.     WHILE dep       -> traverse dependencies
  319.       dep.object:=findobject(dep.object,list)
  320.       dep:=dep.next
  321.     ENDWHILE
  322.     obj:=obj.next
  323.   ENDWHILE
  324.  
  325.   -> CHECK CYCLES!!!
  326.  
  327.   obj:=list
  328.   IF args.target
  329.     WHILE obj
  330.       IF StrCmp(args.target,obj.name) THEN JUMP out
  331.       obj:=obj.next
  332.     ENDWHILE
  333.     Raise("ntar")
  334.     out:
  335.   ELSE
  336.     IF obj THEN WHILE obj.next DO obj:=obj.next
  337.   ENDIF
  338.   traverse(obj)
  339. ENDPROC
  340.  
  341.  
  342. -> find object in list of objects by name
  343. PROC findobject(name:PTR TO CHAR,list:PTR TO object)
  344.   WHILE list
  345.     IF StrCmp(name,list.name)
  346.       -> remove object from root list
  347.       list.child:=TRUE;
  348.       RETURN list
  349.     ENDIF
  350.     list:=list.next
  351.   ENDWHILE
  352. ENDPROC NEW [NIL,name,NIL,NIL]:object
  353.  
  354. -> child-first traversal of dependancy tree
  355. PROC traverse(obj:PTR TO object) -> executes actions in tree
  356.   DEF dep:PTR TO dependancy,maxtime1=0,maxtime2=0,time1,time2,action:PTR TO action,
  357.     oldTarget
  358. /*
  359.  * oldTarget holds the value of target when the proc was entered. It will be set back
  360.  * right before we return from this proc.
  361.  */ 
  362.  
  363.   IF obj.firstdep OR obj.firstaction    -> object with dependancies/actions
  364.     -> traverse children and get maximum timestamp
  365.     dep:=obj.firstdep
  366.     oldTarget:=target -> store it
  367.     target := obj.name
  368.     IF obj.firstdep
  369.       IF obj.firstdep.object THEN depName := obj.firstdep.object.name ELSE depName := ' '
  370.     ENDIF
  371.  
  372.     WHILE dep
  373.       IF OstrCmp (dep.object.name, obj.name) = 0 THEN Throw("circ",obj.name) -> cyclic check by Glauschwuffel
  374.       time1,time2:=traverse(dep.object)
  375.       IF timelater(time1,time2,maxtime1,maxtime2)
  376.         maxtime1:=time1
  377.         maxtime2:=time2
  378.       ENDIF
  379.       dep:=dep.next
  380.     ENDWHILE
  381.     time1,time2:=filetime (obj.name)
  382.     IF time1<0 OR timelater(maxtime1,maxtime2,time1,time2) OR args.force
  383.       -> dependancy file(s) more recent: build object
  384.       -> execute actions
  385. ->      action:=obj.firstaction
  386.  
  387.       buildAndExecuteScript (obj)
  388.  
  389.       time1,time2:=filetime(obj.name)
  390.       IF (time1<0) AND (obj.child=TRUE) THEN Throw("bada",obj.name)
  391.     ENDIF
  392.     target:=oldTarget -> restore it
  393.     RETURN time1,time2
  394.   ENDIF
  395.   -> object requires no action: return timestamp
  396.   time1,time2:=filetime(obj.name);
  397.   IF time1<0 THEN Throw("badd",obj.name)
  398. ENDPROC time1,time2
  399.  
  400. /* - glauschwuffel's stuff --- */
  401.  
  402.  
  403. PROC dumpC()
  404. DEF co:PTR TO constant
  405.   co:=constants
  406.   WriteF ('Constants are:\n') 
  407.   WHILE co  
  408.     WriteF('\s => \s.\n', co.name, co.subst)
  409.     co:=co.next
  410.   ENDWHILE
  411. ENDPROC
  412.  
  413. PROC substituteConstants(c:PTR TO CHAR, s:PTR TO CHAR)
  414. -> search c for constants and substitute them
  415. DEF dollar, bclose=-1,sub=NIL
  416.   REPEAT
  417.     bclose++
  418.     dollar := InStr (c,'$(',bclose)
  419.     IF (dollar<>-1) -> found it?
  420.       StrAdd (s, c+bclose, dollar-bclose)
  421.       bclose := InStr (c,')',dollar+2)
  422.       IF bclose=-1 THEN Throw("clos",c)
  423.       sub := findConstant(c,dollar+2,bclose-1)
  424.       IF sub=NIL OR CtrlC() THEN Throw("cons",c+dollar)
  425.       StrAdd (s,sub)
  426.     ELSE -> copy rest of the line to buffer
  427.       StrAdd (s, c+bclose)
  428.     ENDIF
  429.   UNTIL (dollar=-1) OR (bclose=-1)
  430.   RETURN sub -> did we substitute something at all?
  431. ENDPROC
  432.  
  433. PROC findConstant(c,start,end)
  434. -> find constant of given position in list
  435. -> add 27.07.97: returns global target on target
  436. DEF co:PTR TO constant
  437.  
  438.   IF OstrCmp('target',c+start,end-start+1)=0
  439.     IF target=NIL THEN RETURN '$target' ELSE RETURN target
  440.   ENDIF
  441.  
  442.   IF OstrCmp('dep',c+start,end-start+1)=0
  443.     IF depName=NIL THEN RETURN '$dep' ELSE RETURN depName
  444.   ENDIF
  445.  
  446.   co:=constants
  447.   WHILE co  
  448.     EXIT (OstrCmp(co.name,c+start,end-start+1)=0)
  449.     co:=co.next
  450.   ENDWHILE
  451.   RETURN IF co THEN co.subst ELSE NIL
  452. ENDPROC
  453.  
  454. PROC buildAndExecuteScript (obj:PTR TO object) HANDLE
  455. /*
  456. History:
  457. 16.11.97 glauschwuffel
  458. Introduced new script variable 'dep' which holds the name of the
  459. first dependancy.
  460. */
  461. DEF s[1024]:STRING,
  462.   action:PTR TO action,
  463.   first_dependent_object:PTR TO object,
  464.   handle,
  465.   scriptName[255]:STRING,
  466.   executeLine[255]:STRING
  467.  
  468.   action := obj.firstaction
  469.   first_dependent_object := obj.firstdep.object
  470.  
  471.   StringF(scriptName,'T:Ebuild_actions_\s', args.target)
  472.   handle := Open (scriptName, MODE_NEWFILE) -> open script file
  473.   IF (handle = NIL) THEN Raise ("scrp")
  474.  
  475.   /* create script variable TARGET */
  476.   StrAdd (s, 'Set target ')
  477.   StrAdd (s, target)
  478.   StrAdd (s, '\n') -> add newline
  479.   Write (handle, s, StrLen (s))
  480.   IF args.verbose THEN PrintF('\s', s)
  481.   SetStr (s, 0) -> "delete" the string of the last action
  482.  
  483.   /* create script variable DEP */
  484.   StrAdd (s, 'Set dep ')
  485.   StrAdd (s, IF first_dependent_object THEN first_dependent_object.name ELSE ' ')
  486.   StrAdd (s, '\n') -> add newline
  487.   Write (handle, s, StrLen (s))
  488.   IF args.verbose THEN PrintF('\s', s)
  489.  
  490.   
  491.   WHILE action
  492.     uptodate:=FALSE
  493.     SetStr (s, 0) -> "delete" the string of the last action
  494.     substituteConstants (action.comstring, s) -> expand action
  495.     StrAdd (s, '\n') -> add newline
  496.     IF args.verbose THEN PrintF('\s', s)
  497.     Write (handle, s, StrLen (s))
  498.     action:=action.next
  499.   ENDWHILE
  500.  
  501.   Close (handle)
  502.   StringF(executeLine,'Execute \s', scriptName)
  503.  
  504.   IF SystemTagList(executeLine, NIL)=-1 THEN Raise("derr")
  505.   IF args.mess=0 
  506.     DeleteFile (scriptName)
  507.   ELSE
  508.     WriteF('Script can be found at \s.\n', scriptName)
  509.   ENDIF
  510.  
  511. EXCEPT
  512.   IF handle THEN Close(handle)
  513.   ReThrow()
  514. ENDPROC
  515.  
  516. PROC lookForDirectives (list:PTR TO LONG)
  517. ->22.11.97
  518. DEF i, -> list index
  519.   s:PTR TO CHAR -> current line
  520.  
  521.   FOR i:=0 TO ListLen(list)-1
  522.     s:=ListItem(list,i)
  523.     IF s[0] = "#"
  524.       IF s[1]="i" THEN RETURN includeFile(list,i,s+3)
  525.     ENDIF
  526.   ENDFOR
  527.   RETURN list
  528. ENDPROC
  529.  
  530. PROC includeFile(list:PTR TO LONG,currentIndex,file) HANDLE
  531. ->22.11.97
  532. DEF mem,len,nulist,l
  533.   mem,len:=readfile(file)
  534.   l:=stringsinfile(mem,len,countstrings(mem,len))
  535.  
  536.   nulist := List (ListLen(list)+ListLen(l))
  537.   IF currentIndex>0 THEN ListAdd(nulist,list,currentIndex)
  538.   ListAdd(nulist,l)
  539.   ListAdd(nulist,list+(currentIndex*4)+4,ListLen(list)-currentIndex-1)
  540.   SetList(nulist,ListLen(list)+ListLen(l))
  541.   DisposeLink(list)
  542.   RETURN nulist
  543. EXCEPT
  544.   Throw("inc",file)
  545. ENDPROC
  546.  
  547. versionTag: CHAR 0,'$VER:'
  548. versionString: CHAR 'EBuild 0.97 (23.11.97) ©1997 Rob, Wouter, Jason and Glauschwuffel',0
  549.